#include "epoll_loop.h"
#include "task.h"
#include "timer_loop.h"
#include <cstddef>
#include <iostream>
#include <span>
#include <string_view>
#include <thread>
#include <unistd.h>
#include <vector>

co_async::EpollLoop eloop;
co_async::TimerLoop tloop;

struct IStream {
  std::vector<char> buffer;
  int fd;
  std::size_t index = 0;
  std::size_t size = 0;

  IStream(int fd, std::size_t buf_size = 1024) : fd(fd), buffer(buf_size) {}

  co_async::Task<> read_all() {
    size = co_await co_async::read_file(&eloop, fd, buffer);
    index = 0;
    co_return;
  }

  co_async::Task<char> getchar() {
    if (index == size) {
      co_await read_all();
    }
    co_return buffer[index++];
  }

  co_async::Task<std::string> getline(char end = '\n') {
    std::string line;
    while (true) {
      auto c = co_await getchar();
      line.push_back(c);
      if (c == end) {
        break;
      }
    }
    co_return line;
  }

  co_async::Task<std::string> getline(std::string_view end) {
    std::string line;
    while (true) {
      auto c = co_await getchar();
      line.push_back(c);
      if (line.ends_with(end)) {
        break;
      }
    }
    co_return line;
  }

  co_async::Task<std::string> getn(std::size_t n) {
    std::string line(n, 0);
    for (size_t i = 0; i < n; i++) {
      line[i] = co_await getchar();
    }
    co_return line;
  }
};

co_async::Task<> amain() {
  IStream asin{STDIN_FILENO, 32};
  while (true) {
    auto c = co_await asin.getline(": ");
    std::cout << "read: " << c << std::endl;
    c = co_await asin.getline('\n');
    std::cout << "read: " << c << std::endl;
  }
  co_return;
}

int main() {
  auto t = amain();
  t.get_handle().resume();
  while (true) {
    auto timeout = tloop.run();
    if (eloop.has_event()) {
      eloop.run_once(timeout);
    } else if (timeout) {
      std::this_thread::sleep_for(*timeout);
    } else {
      break;
    }
  }
}